﻿using System;
using System.Reflection;
using System.Collections.Generic;
using System.Linq;
using System.Diagnostics;
using System.Threading.Tasks;

using HslCommunication;
using HslCommunication.Core;
using HslCommunication.Core.Net;
using System.Windows.Forms;

namespace KorbeRTR.Utility.HslWapper
{
    /// <summary>
    /// 变量修饰
    /// </summary>
    [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)]
    public class VariableAttribute : Attribute
    {
        public VariableAttribute()
        {
        }
    }

    /// <summary>
    /// 变量组修饰
    /// 只能修饰Variable
    /// </summary>
    [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)]
    public class VariableGroupAttribute : Attribute
    {
        public VariableGroupAttribute(string area, int addr)
        {
            Area = area.Trim().ToUpper();
            Addr = addr;
        }

        public string Area { get; }
        public int Addr { get; }

        public override string ToString()
        {
            return string.Format("{0}{1}", Area, Addr);
        }
    }

    /// <summary>
    /// 变量自动化注册机
    /// </summary>
    public class VariableRegersterHelper
    {
        public Dictionary<string, Variable> Variables { get; private set; }
        public Dictionary<string, VariableGroup> VariableGroups { get; private set; }

        public VariableRegersterHelper(object parent)
        {
            Variables = new Dictionary<string, Variable>();
            VariableGroups = new Dictionary<string, VariableGroup>();

            RegersterVariable(parent);
        }

        private void RegersterVariable(object parent)
        {
            var vars = parent.GetType().GetFields(BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.Instance);

            foreach (var iter in vars)
            {
                #region 单独变量
                Attribute attr = iter.GetCustomAttribute<VariableAttribute>();
                if (attr != null)
                {
                    var value = iter.GetValue(parent);
                    var type = value.GetType();

                    if (value is Variable)
                    {
                        var tmp = value as Variable;
                        if (tmp.Addr > 0)
                        {
                            Debug.Assert(!Variables.ContainsKey(tmp.HslAddr), Variables.ContainsKey(tmp.HslAddr) ? Variables[tmp.HslAddr].ToString() + " | " + tmp.ToString() : "");
                            Variables[tmp.HslAddr] = tmp;
                        }
                    }
                    else if (type.IsArray)
                    {   // 数组
                        var array = value as Array;

                        if (typeof(Variable).IsAssignableFrom(type.GetElementType()))
                        {
                            foreach (var it in array)
                            {
                                var tmp = it as Variable;
                                if (tmp.Addr > 0)
                                {
                                    Debug.Assert(!Variables.ContainsKey(tmp.HslAddr), Variables.ContainsKey(tmp.HslAddr) ? Variables[tmp.HslAddr].ToString() + " | " + tmp.ToString() : "");
                                    Variables[tmp.HslAddr] = tmp;
                                }
                            }
                        }
                        else
                        {   // 递归
                            foreach (var it in array)
                            {
                                var helper = new VariableRegersterHelper(it);
                                //Variables = Variables.Concat(helper.Variables).ToDictionary(kv => kv.Key, kv => kv.Value);
                                foreach (var itt in helper.Variables)
                                {
                                    var tmp = itt.Value;
                                    if (tmp.Addr > 0)
                                    {
                                        Debug.Assert(!Variables.ContainsKey(tmp.HslAddr), Variables.ContainsKey(tmp.HslAddr) ? Variables[tmp.HslAddr].ToString() + " | " + tmp.ToString() : "");
                                        Variables[tmp.HslAddr] = tmp;
                                    }
                                }
                            }
                        }
                    }
                    else if (type.IsGenericType && type is IEnumerable<object>)
                    {
                        var GAS = type.GetGenericArguments();
                        switch (GAS.Length)
                        {
                            case 1:
                                var list = value as IEnumerable<object>;

                                if (typeof(Variable).IsAssignableFrom(GAS[0].GetType()))
                                {
                                    foreach (var it in list)
                                    {
                                        var tmp = it as Variable;
                                        if (tmp.Addr > 0)
                                        {
                                            Debug.Assert(!Variables.ContainsKey(tmp.HslAddr), Variables.ContainsKey(tmp.HslAddr) ? Variables[tmp.HslAddr].ToString() + " | " + tmp.ToString() : "");
                                            Variables[tmp.HslAddr] = tmp;
                                        }
                                    }
                                }
                                else
                                {
                                    // 递归
                                    foreach (var it in list)
                                    {
                                        var helper = new VariableRegersterHelper(it);
                                        //Variables = Variables.Concat(helper.Variables).ToDictionary(kv => kv.Key, kv => kv.Value);
                                        foreach (var itt in helper.Variables)
                                        {
                                            var tmp = itt.Value;
                                            if (tmp.Addr > 0)
                                            {
                                                Debug.Assert(!Variables.ContainsKey(tmp.HslAddr), Variables.ContainsKey(tmp.HslAddr) ? Variables[tmp.HslAddr].ToString() + " | " + tmp.ToString() : "");
                                                Variables[tmp.HslAddr] = tmp;
                                            }
                                        }
                                    }
                                }
                                break;

                            case 2:
                                if (type is IDictionary<object, object>)
                                {
                                    var dict = value as IDictionary<object, object>;
                                    if (typeof(Variable).IsAssignableFrom(GAS[1].GetType()))
                                    {
                                        foreach (var it in dict)
                                        {
                                            var tmp = it.Value as Variable;
                                            if (tmp.Addr > 0)
                                            {
                                                Debug.Assert(!Variables.ContainsKey(tmp.HslAddr), Variables.ContainsKey(tmp.HslAddr) ? Variables[tmp.HslAddr].ToString() + " | " + tmp.ToString() : "");
                                                Variables[tmp.HslAddr] = tmp;
                                            }
                                        }
                                    }
                                    else
                                    {   // 递归
                                        foreach (var it in dict)
                                        {
                                            var helper = new VariableRegersterHelper(it.Value);
                                            //Variables = Variables.Concat(helper.Variables).ToDictionary(kv => kv.Key, kv => kv.Value);
                                            foreach (var itt in helper.Variables)
                                            {
                                                var tmp = itt.Value;
                                                if (tmp.Addr > 0)
                                                {
                                                    Debug.Assert(!Variables.ContainsKey(tmp.HslAddr), Variables.ContainsKey(tmp.HslAddr) ? Variables[tmp.HslAddr].ToString() + " | " + tmp.ToString() : "");
                                                    Variables[tmp.HslAddr] = tmp;
                                                }
                                            }
                                        }
                                    }
                                }
                                else
                                {
                                    Debug.Assert(false);
                                }
                                break;

                            default:
                                Debug.Assert(false);
                                break;
                        }
                    }
                    else if (type.IsClass)
                    {
                        var helper = new VariableRegersterHelper(value);
                        //Variables = Variables.Concat(helper.Variables).ToDictionary(kv => kv.Key, kv => kv.Value);
                        foreach(var itt in helper.Variables)
                        {
                            var tmp = itt.Value;
                            if (tmp.Addr > 0)
                            {
                                Debug.Assert(!Variables.ContainsKey(tmp.HslAddr), Variables.ContainsKey(tmp.HslAddr) ? Variables[tmp.HslAddr].ToString() + " | " + tmp.ToString() : "");
                                Variables[tmp.HslAddr] = tmp;
                            }
                        }
                    }
                    else
                    {
                        Debug.Assert(false);
                    }
                }
                #endregion

                #region 变量组
                attr = iter.GetCustomAttribute<VariableGroupAttribute>();
                if (attr != null)
                {
                    var value = iter.GetValue(parent);
                    var type = value.GetType();

                    Debug.Assert(value is Variable, "变量组属性只能用于Variable");

                    if (value is Variable)
                    {
                        var att = attr as VariableGroupAttribute;
                        var tmp = value as Variable;

                        tmp.SetGroup(att.Area, att.Addr);
                        if (tmp.Addr > 0)
                        {
                            Debug.Assert(!Variables.ContainsKey(tmp.HslAddr), Variables.ContainsKey(tmp.HslAddr) ? Variables[tmp.HslAddr].ToString() + " | " + tmp.ToString() : "");
                            Variables[tmp.HslAddr] = tmp;
                        }
                    }
                }
                #endregion
            }

            foreach(var iter in Variables)
            {
                if (iter.Value.Group == null) continue;

                var k = iter.Value.Group.ToString();
                var v = iter.Value;

                if (!VariableGroups.ContainsKey(k))
                {
                    VariableGroups[k] = new VariableGroup(v.Group.Area, v.Group.Addr);
                }
                VariableGroups[k].Add(v);
            }
        }
    }

    public abstract class Variable
    {
        public Variable(string Area, int Addr, int? SubAddr, string Comment, VariableGroupAttribute Group)
        {
            this.Area = Area.Trim().ToUpper();
            this.Addr = Addr;
            this.SubAddr = SubAddr;
            this.Comment = Comment;
            this.Group = Group;

            IsWrited = false;
            IsChanged = false;

            if (this.Group != null)
            {
                Debug.Assert(this.Area == this.Group.Area);
            }
        }

        public string HslAddr
        {
            get
            {
                if (SubAddr.HasValue)
                {
                    return string.Format("{0}{1}.{2}", Area, Addr, SubAddr.Value);
                }
                else
                {
                    return string.Format("{0}{1}", Area, Addr);
                }
            }
        }

        /// <summary>
        /// 地址域
        /// </summary>
        public string Area { get; }

        /// <summary>
        /// 地址
        /// </summary>
        public int Addr { get; }

        /// <summary>
        /// 子地址
        /// </summary>
        public int? SubAddr { get; }

        /// <summary>
        /// 备注
        /// </summary>
        public string Comment { get; }

        /// <summary>
        /// 变量大小(字节)
        /// </summary>
        public abstract int Size { get; }

        /// <summary>
        /// 所属变量组
        /// </summary>
        public VariableGroupAttribute Group { get; private set; }

        public void SetGroup(string area, int addr)
        {
            Debug.Assert(area == Area);

            Group = new VariableGroupAttribute(area, addr);
        }

        /// <summary>
        /// 变量被写入
        /// </summary>
        public bool IsWrited { get; protected set; }

        public void ClearWrited()
        {
            IsWrited = false;
        }

        /// <summary>
        /// 变量是否被改变
        /// </summary>
        public bool IsChanged { get; protected set; }

        public void ClearChanged()
        {
            IsChanged = false;
        }

        public abstract string ChangeMessage();

        public abstract OperateResult Pull(IReadWriteNet dev);

        public abstract OperateResult Push(IReadWriteNet dev);

        public abstract Task<OperateResult> PullAsync(IReadWriteNet dev);

        public abstract Task<OperateResult> PushAsync(IReadWriteNet dev);

        public abstract void TransFrom(NetworkDoubleBase dev, byte[] buffer, int UnitSize);

        public abstract string ValueString();

        public override string ToString()
        {
            if (SubAddr.HasValue)
            {
                return string.Format("{0} {1}{2}.{3}", Comment, Area, Addr, SubAddr.Value);
            }
            else
            {
                return string.Format("{0} {1}{2}", Comment, Area, Addr);
            }
        }
    }

    /// <summary>
    /// 变量
    /// </summary>
    /// <typeparam name="TV">视在类型</typeparam>
    /// <typeparam name="TM">实际类型</typeparam>
    public class Variable<TV, TM> : Variable
    {
        #region 单独变量
        public Variable(string Area, int Addr, int? SubAddr = null) : base(Area, Addr, SubAddr, "", null)
        {
        }

        public Variable(string Area, int Addr, string Comment) : base(Area, Addr, null, Comment, null)
        {
        }

        public Variable(string Area, int Addr, int? SubAddr, string Comment) : base(Area, Addr, SubAddr, Comment, null)
        {
        }
        #endregion

        #region 属于变量组
        public Variable(string Area, int Addr, VariableGroupAttribute Group) : base(Area, Addr, null, null, Group)
        {
        }
        public Variable(string Area, int Addr, int SubAddr, VariableGroupAttribute Group) : base(Area, Addr, SubAddr, null, Group)
        {
        }
        public Variable(string Area, int Addr, string Comment, VariableGroupAttribute Group) : base(Area, Addr, null, Comment, Group)
        {
        }
        public Variable(string Area, int Addr, int SubAddr, string Comment, VariableGroupAttribute Group) : base(Area, Addr, SubAddr, Comment, Group)
        {
        }
        #endregion

        /// <summary>
        /// 变量所占字节数
        /// </summary>
        public override int Size
        {
            get
            {
                switch (this)
                {
                    case Variable<TV,bool> tmp: return 1;
                    case Variable<TV,Int16> tmp: return 2;
                    case Variable<TV,UInt16> tmp: return 2;
                    case Variable<TV,Int32> tmp: return 4;
                    case Variable<TV,UInt32> tmp: return 4;
                    case Variable<TV,Int64> tmp: return 8;
                    case Variable<TV,UInt64> tmp: return 8;
                    case Variable<TV,float> tmp: return 4;
                    case Variable<TV,double> tmp: return 8;

                    default: return 1;
                }
            }
        }

        /// <summary>
        /// 原始数据存储
        /// </summary>
        private TM value;

        /// <summary>
        /// 上一个原始数据
        /// </summary>
        private TM last_value;

        /// <summary>
        /// 写入缓存
        /// </summary>
        public TM WriteCache { get; protected set; }

        public void UpdateRawValue(TM v)
        {
            last_value = value;
            value = v;
            if (!last_value.Equals(value))
            {
                IsChanged = true;
            }
        }

        /// <summary>
        /// 原始值
        /// </summary>
        public TM RawValue
        {
            get
            {
                return value;
            }
            set
            {
                WriteCache = value;
                IsWrited = true;
            }
        }

        /// <summary>
        /// 视在值
        /// </summary>
        public virtual TV Value
        {
            get
            {
                return (TV)Convert.ChangeType(RawValue, typeof(TV));
            }
            set
            {
                RawValue = (TM)Convert.ChangeType(value, typeof(TM));
            }
        }

        public TM LastRawValue => last_value;

        public virtual TV LastValue
        {
            get
            {
                return (TV)Convert.ChangeType(LastRawValue, typeof(TV));
            }
        }


        public static implicit operator TV(Variable<TV, TM> x)
        {
            return x.Value;
        }

        public override string ChangeMessage()
        {
            switch (this)
            {
                case Variable<bool, TM> tmp: return string.Format("{0}: {1} -> {2}", tmp.Comment, tmp.LastValue? "ON" : "OFF", tmp.Value? "ON" : "OFF");
                case Variable<Int16, TM> tmp: return string.Format("{0}: {1} -> {2}", tmp.Comment, tmp.LastValue, tmp.Value);
                case Variable<UInt16, TM> tmp: return string.Format("{0}: {1} -> {2}", tmp.Comment, tmp.LastValue, tmp.Value);
                case Variable<Int32, TM> tmp: return string.Format("{0}: {1} -> {2}", tmp.Comment, tmp.LastValue, tmp.Value);
                case Variable<UInt32, TM> tmp: return string.Format("{0}: {1} -> {2}", tmp.Comment, tmp.LastValue, tmp.Value);
                case Variable<Int64, TM> tmp: return string.Format("{0}: {1} -> {2}", tmp.Comment, tmp.LastValue, tmp.Value);
                case Variable<UInt64, TM> tmp: return string.Format("{0}: {1} -> {2}", tmp.Comment, tmp.LastValue, tmp.Value);
                case Variable<float, TM> tmp: return string.Format("{0}: {1} -> {2}", tmp.Comment, tmp.LastValue, tmp.Value);
                case Variable<double, TM> tmp: return string.Format("{0}: {1} -> {2}", tmp.Comment, tmp.LastValue, tmp.Value);

                default: throw new Exception("类型不支持");
            }
        }

        public override OperateResult Pull(IReadWriteNet dev)
        {
            switch (this)
            {
                case Variable<TV,bool> tmp: return dev.Pull(tmp);
                case Variable<TV,Int16> tmp: return dev.Pull(tmp);
                case Variable<TV,UInt16> tmp: return dev.Pull(tmp);
                case Variable<TV,Int32> tmp: return dev.Pull(tmp);
                case Variable<TV,UInt32> tmp: return dev.Pull(tmp);
                case Variable<TV,Int64> tmp: return dev.Pull(tmp);
                case Variable<TV,UInt64> tmp: return dev.Pull(tmp);
                case Variable<TV,float> tmp: return dev.Pull(tmp);
                case Variable<TV,double> tmp: return dev.Pull(tmp);

                default: throw new Exception("类型不支持");
            }
        }

        public override OperateResult Push(IReadWriteNet dev)
        {
            switch (this)
            {
                case Variable<TV,bool> tmp: return dev.Push(tmp);
                case Variable<TV,Int16> tmp: return dev.Push(tmp);
                case Variable<TV,UInt16> tmp: return dev.Push(tmp);
                case Variable<TV,Int32> tmp: return dev.Push(tmp);
                case Variable<TV,UInt32> tmp: return dev.Push(tmp);
                case Variable<TV,Int64> tmp: return dev.Push(tmp);
                case Variable<TV,UInt64> tmp: return dev.Push(tmp);
                case Variable<TV,float> tmp: return dev.Push(tmp);
                case Variable<TV,double> tmp: return dev.Push(tmp);

                default: throw new Exception("类型不支持");
            }
        }

        public override async Task<OperateResult> PullAsync(IReadWriteNet dev)
        {
            switch (this)
            {
                case Variable<TV,bool> tmp: return await dev.PullAsync(tmp);
                case Variable<TV,Int16> tmp: return await dev.PullAsync(tmp);
                case Variable<TV,UInt16> tmp: return await dev.PullAsync(tmp);
                case Variable<TV,Int32> tmp: return await dev.PullAsync(tmp);
                case Variable<TV,UInt32> tmp: return await dev.PullAsync(tmp);
                case Variable<TV,Int64> tmp: return await dev.PullAsync(tmp);
                case Variable<TV,UInt64> tmp: return await dev.PullAsync(tmp);
                case Variable<TV,float> tmp: return await dev.PullAsync(tmp);
                case Variable<TV,double> tmp: return await dev.PullAsync(tmp);

                default: throw new Exception("类型不支持");
            }
        }

        public override async Task<OperateResult> PushAsync(IReadWriteNet dev)
        {
            switch (this)
            {
                case Variable<TV,bool> tmp: return await dev.PushAsync(tmp);
                case Variable<TV,Int16> tmp: return await dev.PushAsync(tmp);
                case Variable<TV,UInt16> tmp: return await dev.PushAsync(tmp);
                case Variable<TV,Int32> tmp: return await dev.PushAsync(tmp);
                case Variable<TV,UInt32> tmp: return await dev.PushAsync(tmp);
                case Variable<TV,Int64> tmp: return await dev.PushAsync(tmp);
                case Variable<TV,UInt64> tmp: return await dev.PushAsync(tmp);
                case Variable<TV,float> tmp: return await dev.PushAsync(tmp);
                case Variable<TV,double> tmp: return await dev.PushAsync(tmp);

                default: throw new Exception("类型不支持");
            }
        }

        public override void TransFrom(NetworkDoubleBase dev, byte[] buffer, int UnitSize)
        {
            Debug.Assert(UnitSize == 1 || UnitSize == 2);
            Debug.Assert(Group != null);

            switch (this)
            {
                case Variable<TV,bool> tmp:
                {
                    int offset = Addr - Group.Addr;
                    offset *= UnitSize;

                    if (tmp.SubAddr.HasValue)
                    {
                        if (UnitSize == 1)
                        {
                            byte t = dev.ByteTransform.TransByte(buffer, offset);
                            byte mask = (byte)(1 << tmp.SubAddr.Value);
                            tmp.UpdateRawValue((t & mask) == mask);
                        }
                        else if (UnitSize == 2)
                        {
                            UInt16 t = dev.ByteTransform.TransUInt16(buffer, offset);
                            UInt16 mask = (UInt16)(1 << tmp.SubAddr.Value);
                            tmp.UpdateRawValue((t & mask) == mask);
                        }
                        else
                        {
                            throw new Exception("UnitSize 只能是 1 或 2");
                        }
                    }
                    else
                    {
                        tmp.UpdateRawValue(dev.ByteTransform.TransBool(buffer, offset));
                    }

                    break;
                }
                case Variable<TV,Int16> tmp:
                {
                    int offset = Addr - Group.Addr;
                    offset *= UnitSize;

                    tmp.UpdateRawValue(dev.ByteTransform.TransInt16(buffer, offset));

                    break;
                }
                case Variable<TV, UInt16> tmp:
                {
                    int offset = Addr - Group.Addr;
                    offset *= UnitSize;

                    tmp.UpdateRawValue(dev.ByteTransform.TransUInt16(buffer, offset));

                    break;
                }
                case Variable<TV, Int32> tmp:
                {
                    int offset = Addr - Group.Addr;
                    offset *= UnitSize;

                    tmp.UpdateRawValue(dev.ByteTransform.TransInt32(buffer, offset));

                    break;
                }
                case Variable<TV, UInt32> tmp:
                {
                    int offset = Addr - Group.Addr;
                    offset *= UnitSize;

                    tmp.UpdateRawValue(dev.ByteTransform.TransUInt32(buffer, offset));

                    break;
                }
                case Variable<TV, Int64> tmp:
                {
                    int offset = Addr - Group.Addr;
                    offset *= UnitSize;

                    tmp.UpdateRawValue(dev.ByteTransform.TransInt64(buffer, offset));

                    break;
                }
                case Variable<TV, UInt64> tmp:
                {
                    int offset = Addr - Group.Addr;
                    offset *= UnitSize;

                    tmp.UpdateRawValue(dev.ByteTransform.TransUInt64(buffer, offset));

                    break;
                }
                case Variable<TV, float> tmp:
                {
                    int offset = Addr - Group.Addr;
                    offset *= UnitSize;

                    tmp.UpdateRawValue(dev.ByteTransform.TransSingle(buffer, offset));

                    break;
                }
                case Variable<TV, double> tmp:
                {
                    int offset = Addr - Group.Addr;
                    offset *= UnitSize;

                    tmp.UpdateRawValue(dev.ByteTransform.TransDouble(buffer, offset));

                    break;
                }

                default: throw new Exception("类型不支持");
            }
        }

        public override string ValueString()
        {
            switch (this)
            {
                case Variable<bool, TM> tmp: return tmp.Value.ToString();
                case Variable<Int16, TM> tmp: return tmp.Value.ToString();
                case Variable<UInt16, TM> tmp: return tmp.Value.ToString();
                case Variable<Int32, TM> tmp: return tmp.Value.ToString();
                case Variable<UInt32, TM> tmp: return tmp.Value.ToString();
                case Variable<Int64, TM> tmp: return tmp.Value.ToString();
                case Variable<UInt64, TM> tmp: return tmp.Value.ToString();
                case Variable<float, TM> tmp: return tmp.Value.ToString();
                case Variable<double, TM> tmp: return tmp.Value.ToString();

                default: throw new Exception("类型不支持");
            }
        }
    }

    public class Variable<T> : Variable<T,T>
    {
        #region 单独变量
        public Variable(string Area, int Addr, int? SubAddr = null) : base(Area, Addr, SubAddr)
        {
        }

        public Variable(string Area, int Addr, string Comment) : base(Area, Addr, null, Comment)
        {
        }

        public Variable(string Area, int Addr, int? SubAddr, string Comment) : base(Area, Addr, SubAddr, Comment)
        {
        }
        #endregion

        #region 属于变量组
        public Variable(string Area, int Addr, VariableGroupAttribute Group): base(Area, Addr, Group)
        {
        }
        public Variable(string Area, int Addr, int SubAddr, VariableGroupAttribute Group): base(Area, Addr, SubAddr, Group)
        {
        }
        public Variable(string Area, int Addr, string Comment, VariableGroupAttribute Group) : base(Area, Addr, Comment, Group)
        {
        }
        public Variable(string Area, int Addr, int SubAddr, string Comment, VariableGroupAttribute Group) : base(Area, Addr, SubAddr, Comment, Group)
        {
        }
        #endregion

        /// <summary>
        /// 视在值
        /// </summary>
        public override T Value
        {
            get => RawValue;
            set => RawValue = value;
        }
    }

    public class VariableGroup
    {
        public VariableGroup(string area, int addr)
        {
            Area = area.Trim().ToUpper();
            Addr = addr;

            MaxAddrVariable = null;

            Variables = new Dictionary<string, Variable>();
        }

        public string Area { get; private set; }
        public int Addr { get; private set; }

        public string HslAddr => string.Format("{0}{1}", Area, Addr);

        public Variable MaxAddrVariable { get; private set; }

        public Dictionary<string, Variable> Variables { get; private set; }

        public Variable Add(Variable v)
        {
            Debug.Assert(Area == v.Area);
            Debug.Assert(Addr <= v.Addr);

            Variables[v.HslAddr] = v;

            if (MaxAddrVariable == null)
            {
                MaxAddrVariable = v;
            }

            if (v.Addr > MaxAddrVariable.Addr)
                MaxAddrVariable = v;

            return v;
        }

        public static implicit operator VariableGroup(VariableGroupAttribute attr)
        {
            return new VariableGroup(attr.Area, attr.Addr);
        }

        public OperateResult Pull(IReadWriteNet dev, int UnitSize)
        {
            Debug.Assert(UnitSize == 1 || UnitSize == 2);

            int len = MaxAddrVariable.Addr - Addr + MaxAddrVariable.Size + (MaxAddrVariable.Size / UnitSize);
            var r = dev.Read(HslAddr, (ushort)len);
            if (r.IsSuccess)
            {
                foreach (var iter in Variables)
                {
                    iter.Value.TransFrom(dev as NetworkDoubleBase, r.Content, UnitSize);
                }
            }

            return r;
        }
    }

    public class Device
    {
        public Device(IReadWriteNet dev, int UnitSize)
        {
            Debug.Assert(UnitSize == 1 || UnitSize == 2);

            NetHandle = dev;

            this.UnitSize = UnitSize;

            Variables = new Dictionary<string, Variable>();
            VariableGroups = new Dictionary<string, VariableGroup>();
        }

        public OperateResult ConnectServer()
        {
            return (NetHandle as HslCommunication.Core.Net.NetworkDeviceBase).ConnectServer();
        }

        public OperateResult DisconnectServer()
        {
            return (NetHandle as HslCommunication.Core.Net.NetworkDeviceBase).ConnectClose();
        }

        public OperateResult Pull()
        {
            OperateResult r = null;

            // 爬取组变量
            foreach (var iter in VariableGroups)
            {
                var result = iter.Value.Pull(NetHandle, UnitSize);
                if (!result.IsSuccess)
                {
                    return result;
                }
            }

            // 拉取单独变量
            foreach (var iter in Variables)
            {
                if (iter.Value.Group == null)
                {
                    var result = iter.Value.Pull(NetHandle);
                    if (!result.IsSuccess)
                    {
                        r = result;
                    }
                }
            }

            return null;
        }

        public OperateResult Push()
        {
            OperateResult r = null;
            foreach(var iter in Variables)
            {
                if (iter.Value.IsWrited)
                {
                    var result = iter.Value.Push(NetHandle);
                    if (!result.IsSuccess)
                    {
                        r = result;
                    }
                }
            }
            return r;
        }

        /// <summary>
        /// 地址单元字节数
        /// </summary>
        public int UnitSize { get; private set; }

        /// <summary>
        /// PLC 变量
        /// </summary>
        public Dictionary<string, Variable> Variables { get; private set; }

        /// <summary>
        /// PLC 变量组
        /// </summary>
        public Dictionary<string, VariableGroup> VariableGroups { get; private set; }

        /// <summary>
        /// 设备读写句柄
        /// </summary>
        public IReadWriteNet NetHandle { get; private set; }

        /// <summary>
        /// 设备额外读写句柄
        /// </summary>
        public IReadWriteDevice DeviceHandle => NetHandle as IReadWriteDevice;


        public void RegersterVariables(object obj)
        {
            try
            {
                var helper = new VariableRegersterHelper(obj);

                Variables = helper.Variables;
                VariableGroups = helper.VariableGroups;
            }
            catch(Exception err)
            {
                MessageBox.Show(err.Message + Environment.NewLine + err.StackTrace);
            }
        }
    }

    /// <summary>
    /// Variable 扩展方法
    /// </summary>
    public static class VariableExtensions
    {
        /// <summary>
        /// bool 同步读
        /// </summary>
        public static OperateResult<bool> Pull<TV>(this IReadWriteNet dev, Variable<TV,bool> value)
        {
            var r = dev.ReadBool(value.HslAddr);
            if (r.IsSuccess)
            {
                value.UpdateRawValue(r.Content);
            }
            return r;
        }

        /// <summary>
        /// bool 同步写
        /// </summary>
        public static OperateResult Push<TV>(this IReadWriteNet dev, Variable<TV,bool> value)
        {
            var r = dev.Write(value.HslAddr, value.WriteCache);
            if (r.IsSuccess)
            {
                value.ClearWrited();
            }
            return r;
        }

        /// <summary>
        /// Int16 同步读
        /// </summary>
        public static OperateResult<Int16> Pull<TV>(this IReadWriteNet dev, Variable<TV, Int16> value)
        {
            var r = dev.ReadInt16(value.HslAddr);
            if (r.IsSuccess)
            {
                value.UpdateRawValue(r.Content);
            }
            return r;
        }

        /// <summary>
        /// Int16 同步写
        /// </summary>
        public static OperateResult Push<TV>(this IReadWriteNet dev, Variable<TV, Int16> value)
        {
            var r = dev.Write(value.HslAddr, value.WriteCache);
            if (r.IsSuccess)
            {
                value.ClearWrited();
            }
            return r;
        }

        /// <summary>
        /// UInt16 同步读
        /// </summary>
        public static OperateResult<UInt16> Pull<TV>(this IReadWriteNet dev, Variable<TV, UInt16> value)
        {
            var r = dev.ReadUInt16(value.HslAddr);
            if (r.IsSuccess)
            {
                value.UpdateRawValue(r.Content);
            }
            return r;
        }

        /// <summary>
        /// UInt16 同步写
        /// </summary>
        public static OperateResult Push<TV>(this IReadWriteNet dev, Variable<TV, UInt16> value)
        {
            var r = dev.Write(value.HslAddr, value.WriteCache);
            if (r.IsSuccess)
            {
                value.ClearWrited();
            }
            return r;
        }

        /// <summary>
        /// Int32 同步读
        /// </summary>
        public static OperateResult<Int32> Pull<TV>(this IReadWriteNet dev, Variable<TV, Int32> value)
        {
            var r = dev.ReadInt32(value.HslAddr);
            if (r.IsSuccess)
            {
                value.UpdateRawValue(r.Content);
            }
            return r;
        }

        /// <summary>
        /// Int32 同步写
        /// </summary>
        public static OperateResult Push<TV>(this IReadWriteNet dev, Variable<TV, Int32> value)
        {
            var r = dev.Write(value.HslAddr, value.WriteCache);
            if (r.IsSuccess)
            {
                value.ClearWrited();
            }
            return r;
        }

        /// <summary>
        /// UInt32 同步读
        /// </summary>
        public static OperateResult<UInt32> Pull<TV>(this IReadWriteNet dev, Variable<TV, UInt32> value)
        {
            var r = dev.ReadUInt32(value.HslAddr);
            if (r.IsSuccess)
            {
                value.UpdateRawValue(r.Content);
            }
            return r;
        }

        /// <summary>
        /// UInt32 同步写
        /// </summary>
        public static OperateResult Push<TV>(this IReadWriteNet dev, Variable<TV, UInt32> value)
        {
            var r = dev.Write(value.HslAddr, value.WriteCache);
            if (r.IsSuccess)
            {
                value.ClearWrited();
            }
            return r;
        }

        /// <summary>
        /// Int64 同步读
        /// </summary>
        public static OperateResult<Int64> Pull<TV>(this IReadWriteNet dev, Variable<TV, Int64> value)
        {
            var r = dev.ReadInt64(value.HslAddr);
            if (r.IsSuccess)
            {
                value.UpdateRawValue(r.Content);
            }
            return r;
        }

        /// <summary>
        /// Int64 同步写
        /// </summary>
        public static OperateResult Push<TV>(this IReadWriteNet dev, Variable<TV, Int64> value)
        {
            var r = dev.Write(value.HslAddr, value.WriteCache);
            if (r.IsSuccess)
            {
                value.ClearWrited();
            }
            return r;
        }

        /// <summary>
        /// UInt64 同步读
        /// </summary>
        public static OperateResult<UInt64> Pull<TV>(this IReadWriteNet dev, Variable<TV, UInt64> value)
        {
            var r = dev.ReadUInt64(value.HslAddr);
            if (r.IsSuccess)
            {
                value.UpdateRawValue(r.Content);
            }
            return r;
        }

        /// <summary>
        /// UInt64 同步写
        /// </summary>
        public static OperateResult Push<TV>(this IReadWriteNet dev, Variable<TV, UInt64> value)
        {
            var r = dev.Write(value.HslAddr, value.WriteCache);
            if (r.IsSuccess)
            {
                value.ClearWrited();
            }
            return r;
        }

        /// <summary>
        /// float 同步读
        /// </summary>
        public static OperateResult<float> Pull<TV>(this IReadWriteNet dev, Variable<TV, float> value)
        {
            var r = dev.ReadFloat(value.HslAddr);
            if (r.IsSuccess)
            {
                value.UpdateRawValue(r.Content);
            }
            return r;
        }

        /// <summary>
        /// float 同步写
        /// </summary>
        public static OperateResult Push<TV>(this IReadWriteNet dev, Variable<TV, float> value)
        {
            var r = dev.Write(value.HslAddr, value.WriteCache);
            if (r.IsSuccess)
            {
                value.ClearWrited();
            }
            return r;
        }

        /// <summary>
        /// double 同步读
        /// </summary>
        public static OperateResult<double> Pull<TV>(this IReadWriteNet dev, Variable<TV, double> value)
        {
            var r = dev.ReadDouble(value.HslAddr);
            if (r.IsSuccess)
            {
                value.UpdateRawValue(r.Content);
            }
            return r;
        }

        /// <summary>
        /// double 同步写
        /// </summary>
        public static OperateResult Push<TV>(this IReadWriteNet dev, Variable<TV, double> value)
        {
            var r = dev.Write(value.HslAddr, value.WriteCache);
            if (r.IsSuccess)
            {
                value.ClearWrited();
            }
            return r;
        }

        /// <summary>
        /// bool 异步读
        /// </summary>
        public async static Task<OperateResult<bool>> PullAsync<TV>(this IReadWriteNet dev, Variable<TV, bool> value)
        {
            var r = await dev.ReadBoolAsync(value.HslAddr);
            if (r.IsSuccess)
            {
                value.UpdateRawValue(r.Content);
            }
            return r;
        }

        /// <summary>
        /// bool 异步写
        /// </summary>
        public async static Task<OperateResult> PushAsync<TV>(this IReadWriteNet dev, Variable<TV, bool> value)
        {
            var r = await dev.WriteAsync(value.HslAddr, value.WriteCache);
            if (r.IsSuccess)
            {
                value.ClearWrited();
            }
            return r;
        }

        /// <summary>
        /// Int16 异步读
        /// </summary>
        public async static Task<OperateResult<Int16>> PullAsync<TV>(this IReadWriteNet dev, Variable<TV, Int16> value)
        {
            var r = await dev.ReadInt16Async(value.HslAddr);
            if (r.IsSuccess)
            {
                value.UpdateRawValue(r.Content);
            }
            return r;
        }

        /// <summary>
        /// Int16 异步写
        /// </summary>
        public async static Task<OperateResult> PushAsync<TV>(this IReadWriteNet dev, Variable<TV, Int16> value)
        {
            var r = await dev.WriteAsync(value.HslAddr, value.WriteCache);
            if (r.IsSuccess)
            {
                value.ClearWrited();
            }
            return r;
        }

        /// <summary>
        /// UInt16 异步读
        /// </summary>
        public async static Task<OperateResult<UInt16>> PullAsync<TV>(this IReadWriteNet dev, Variable<TV, UInt16> value)
        {
            var r = await dev.ReadUInt16Async(value.HslAddr);
            if (r.IsSuccess)
            {
                value.UpdateRawValue(r.Content);
            }
            return r;
        }

        /// <summary>
        /// UInt16 异步写
        /// </summary>
        public async static Task<OperateResult> PushAsync<TV>(this IReadWriteNet dev, Variable<TV, UInt16> value)
        {
            var r = await dev.WriteAsync(value.HslAddr, value.WriteCache);
            if (r.IsSuccess)
            {
                value.ClearWrited();
            }
            return r;
        }

        /// <summary>
        /// Int32 异步读
        /// </summary>
        public async static Task<OperateResult<Int32>> PullAsync<TV>(this IReadWriteNet dev, Variable<TV, Int32> value)
        {
            var r = await dev.ReadInt32Async(value.HslAddr);
            if (r.IsSuccess)
            {
                value.UpdateRawValue(r.Content);
            }
            return r;
        }

        /// <summary>
        /// Int32 异步写
        /// </summary>
        public async static Task<OperateResult> PushAsync<TV>(this IReadWriteNet dev, Variable<TV, Int32> value)
        {
            var r = await dev.WriteAsync(value.HslAddr, value.WriteCache);
            if (r.IsSuccess)
            {
                value.ClearWrited();
            }
            return r;
        }

        /// <summary>
        /// UInt32 异步读
        /// </summary>
        public async static Task<OperateResult<UInt32>> PullAsync<TV>(this IReadWriteNet dev, Variable<TV, UInt32> value)
        {
            var r = await dev.ReadUInt32Async(value.HslAddr);
            if (r.IsSuccess)
            {
                value.UpdateRawValue(r.Content);
            }
            return r;
        }

        /// <summary>
        /// UInt32 异步写
        /// </summary>
        public async static Task<OperateResult> PushAsync<TV>(this IReadWriteNet dev, Variable<TV, UInt32> value)
        {
            var r = await dev.WriteAsync(value.HslAddr, value.WriteCache);
            if (r.IsSuccess)
            {
                value.ClearWrited();
            }
            return r;
        }

        /// <summary>
        /// Int64 异步读
        /// </summary>
        public async static Task<OperateResult<Int64>> PullAsync<TV>(this IReadWriteNet dev, Variable<TV, Int64> value)
        {
            var r = await dev.ReadInt64Async(value.HslAddr);
            if (r.IsSuccess)
            {
                value.UpdateRawValue(r.Content);
            }
            return r;
        }

        /// <summary>
        /// Int64 异步写
        /// </summary>
        public async static Task<OperateResult> PushAsync<TV>(this IReadWriteNet dev, Variable<TV, Int64> value)
        {
            var r = await dev.WriteAsync(value.HslAddr, value.WriteCache);
            if (r.IsSuccess)
            {
                value.ClearWrited();
            }
            return r;
        }

        /// <summary>
        /// UInt64 异步读
        /// </summary>
        public async static Task<OperateResult<UInt64>> PullAsync<TV>(this IReadWriteNet dev, Variable<TV, UInt64> value)
        {
            var r = await dev.ReadUInt64Async(value.HslAddr);
            if (r.IsSuccess)
            {
                value.UpdateRawValue(r.Content);
            }
            return r;
        }

        /// <summary>
        /// UInt64 异步写
        /// </summary>
        public async static Task<OperateResult> PushAsync<TV>(this IReadWriteNet dev, Variable<TV, UInt64> value)
        {
            var r = await dev.WriteAsync(value.HslAddr, value.WriteCache);
            if (r.IsSuccess)
            {
                value.ClearWrited();
            }
            return r;
        }

        /// <summary>
        /// float 异步读
        /// </summary>
        public async static Task<OperateResult<float>> PullAsync<TV>(this IReadWriteNet dev, Variable<TV, float> value)
        {
            var r = await dev.ReadFloatAsync(value.HslAddr);
            if (r.IsSuccess)
            {
                value.UpdateRawValue(r.Content);
            }
            return r;
        }

        /// <summary>
        /// float 异步写
        /// </summary>
        public async static Task<OperateResult> PushAsync<TV>(this IReadWriteNet dev, Variable<TV, float> value)
        {
            var r = await dev.WriteAsync(value.HslAddr, value.WriteCache);
            if (r.IsSuccess)
            {
                value.ClearWrited();
            }
            return r;
        }

        /// <summary>
        /// double 异步读
        /// </summary>
        public async static Task<OperateResult<double>> PullAsync<TV>(this IReadWriteNet dev, Variable<TV, double> value)
        {
            var r = await dev.ReadDoubleAsync(value.HslAddr);
            if (r.IsSuccess)
            {
                value.UpdateRawValue(r.Content);
            }
            return r;
        }

        /// <summary>
        /// double 异步写
        /// </summary>
        public async static Task<OperateResult> PushAsync<TV>(this IReadWriteNet dev, Variable<TV, double> value)
        {
            var r = await dev.WriteAsync(value.HslAddr, value.WriteCache);
            if (r.IsSuccess)
            {
                value.ClearWrited();
            }
            return r;
        }
    }
}
